package com.jackrain.nea.common;

import com.jackrain.nea.core.redis.CusRedisTemplate;
import com.jackrain.nea.util.RedisOpsUtil;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 实现分布式锁
 */
public class RedisLocker {
    private static final long DEFAULT_TIMEOUT_MILLISECONDS = 1 * 24 * 60 * 60 * 1000;
    private static final String KEY_PREFIX = "com.jackrain.nea.common.RedisLocker:";
    private String key;
    private String token;
    private CusRedisTemplate<Object, Object> redisTemplate;

    public RedisLocker(String key) {
        if (key != null){
            this.key = KEY_PREFIX + key;
        }
        this.token = UUID.randomUUID().toString();
    }

    /**
     * 默认时间解锁
     * @return
     */
    public boolean lock() {
        return lock(DEFAULT_TIMEOUT_MILLISECONDS);
    }

    /**
     * 指定时间上锁
     * @param timeoutMilliseconds
     * @return true上锁成功  false上锁失败
     */
    public boolean lock(long timeoutMilliseconds) {

        if (key == null) return true;
        if (redisTemplate == null) {
            redisTemplate = RedisOpsUtil.getStrRedisTemplate();
        }
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(key, token);

        if (ifAbsent) {
            redisTemplate.expire(key, timeoutMilliseconds, TimeUnit.MILLISECONDS);
            return true;
        }

        return isMine();
    }


    /**
     * 立即解锁
     * @return
     */
    public boolean unLock() {
        return unLock(-1);
    }

    /**
     * 指定时间解锁
     * @param delayMilliseconds
     * @return
     */
    public boolean unLock(long delayMilliseconds) {
        if (key == null) return true;
        if (isMine()) {
            if (delayMilliseconds <= 0) {
                redisTemplate.delete(key);
            } else {
                redisTemplate.expire(key, delayMilliseconds, TimeUnit.MILLISECONDS);
            }
            return true;
        }
        return false;
    }

    /**
     * 校验redis
     * @return
     */
    public boolean isMine(){
        if(redisTemplate == null){
            return  false;
        }
        return token.equals(redisTemplate.opsForValue().get(key));
    }
}
